/***********************************************************************************************//**
*\n  @file       can_msg.c
*\n  @brief      发送can报文
*\n  @details
*\n -----------------------------------------------------------------------------------
*\n  文件说明：
*\n       1. 解析消息文件;
*\n       2. 从文件中读取信息配置can接口的波特率
*\n       1. 从文件中依次读取can报文，并发送
*\n
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.4.14    创建
*\n
***************************************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <net/if.h>

#include <linux/can.h>
#include <linux/can/raw.h>

#include "vme.h"
#include "socketcan.h"
#include "netcan.h"
#include "can_send.h"

#undef   debug_printf_LEVEL
#define  debug_printf_LEVEL  5
#include "vdebug.h"

enum
{
	STANDARD_FRAME = 0, // 标准帧
	EXTENDED_FRARM = 1, // 扩展帧
};
enum
{
	FLAG_DATA_FRAME = 0,   // 数据帧
	FLAG_REMOTE_FRAME = 1, // 远程帧
};

//static XCanPs Can;

struct massage
{
	u32 bandrate; 	///< 波特率kbps
	u32 type;	 	///< 帧格式 0=std， 1=exts
	u32 id;		  	///< id
	u32 flag;	 	///< 0=数据帧，1=远程帧
	u32 length;   	///< 数据长度0~8
	u8 buf[8];		///< 数据
};

static struct can_handle *handle;

// 打开can
static int openCan(int id, struct massage *msg)
{

	if (id == 0)
	{
		handle = netcan_open("can0", msg->bandrate*1000, 0, NULL);
		if (handle == NULL)
			return -1;
	}
	else if (id == 1)
	{
		handle = netcan_open("can1", msg->bandrate*1000, 0, NULL);
		if (handle == NULL)
			return -1;
	}

	return 0;
}

// 关闭can
static int closeCan(int id)
{
	netcan_close(handle);
	handle = NULL;

	return 0;
}

//发送message到can
static int writeCan(struct massage *msg)
{
	int ret = 0;
	// 发送报文
	if (msg->type)
		ret = netcan_write(handle, msg->id | CAN_EXTEND_FLAG, msg->buf, msg->length);
	else
		ret = netcan_write(handle, msg->id, msg->buf, msg->length);

	return ret;
}

// 从文件数据中读取波特率, 返回0=successfull， 1=false
static int read_bandrate(int *mem_addr, int *length, /*out*/ struct massage *msg)
{
	if ((mem_addr == NULL) || (length == NULL) || (msg == NULL))
	{
		debug_printf("read_bandrate() error\n");
		return 1;
	}
	int size = *length;
	if (size <= 0)
	{
		debug_printf(" length <= 0\n" );
		return 1;
	}

	// 文件尾处理
	char *file_start = (char *)(*mem_addr);
	char *file_end = file_start + size - 1;
	*(file_end + 1) = '\0'; // 文件末尾设置0

	// 查找行
	char *line_start = file_start;
	char *line_end;
loop1:
	for (line_end = line_start; line_end < file_end; line_end++)
	{
		if (*line_end == '\n')
			goto next1;
	}
	debug_printf(" not find EOL \n");
	*length = 0;
	return 1;

	int line_size;
next1:
	line_size = (int)(line_end - line_start) + 1;
	*length -= line_size;
	*mem_addr = (int)line_end + 1; // 指向下一行

	// copy一行数据到buffer并处理
	static char buffer[0x400];
	memset(buffer, 0, sizeof(buffer));
	if (line_size > (sizeof(buffer) - 1))
	{
		line_size = (sizeof(buffer) - 1);
	}
	memcpy(buffer, line_start, line_size);
	// 处理注释
	char *commit = strchr(buffer, '#');
	if (commit != NULL)
	{
		*commit = '\0';
	}

	// buffer中查找行： "bandrate={100} 	   "
	line_start = strstr(buffer, "bandrate");
	if (NULL == line_start)
	{
		// 当前行没有找到bandrate，继续处理下一行。
		//xil_printf("%s,%d,not find string \"bandrate\" \n", __func__, __LINE__);
		line_start = line_end + 1; // 指向下一行
		goto loop1;
		//return 1;
	}

	// 检测括号，提取参数值
	char *braces_end = strchr(line_start, '}');
	if (braces_end == NULL)
	{
		*length = 0;
		printf("%s,%d,not find  } \n", __func__, __LINE__);
		return 1;
	}
	*braces_end = '\0';
	char *braces_start = strchr(line_start, '{');
	if (braces_start == NULL)
	{
		*length = 0;
		printf("%s,%d,not find	{ \n", __func__, __LINE__);
		return 1;
	}
	// 去掉前面空格
	char *num_start;
	for (num_start = braces_start + 1; *num_start != '\0'; num_start++)
	{
		if ((*num_start != ' ') && (*num_start != '\t'))
		{
			goto NEXT1;
		}
	}
	*length = 0;
	return 1;

	int bandrate;
NEXT1:
	bandrate = strtoul(num_start, NULL, 0);
	if (bandrate == 0)
	{
		printf("%s,%d, not find bandrate \n", __func__, __LINE__);
		return 1;
	}

	//xil_printf("bandrate = %d kbps \n",  bandrate);
	msg->bandrate = bandrate;
	return 0;
}

static char *read_args(char **addr)
{
	if (addr == NULL)
		return NULL;
	if (*addr == NULL)
		return NULL;
	if ((**addr) == '\0')
		return NULL;

	// 去掉前面的空格等;
	char **ppAddr;
	for (ppAddr = addr; **ppAddr != '\0'; (*ppAddr)++)
	{
		if ((**ppAddr != ' ') && (**ppAddr != '\t'))
		{
			goto NEXT1;
		}
	}
	return NULL;

	// 检测尾部的 ";"
	char *args_string;
NEXT1:
	args_string = *ppAddr;
	for (; **ppAddr != '\0'; (*ppAddr)++)
	{
		if (**ppAddr == ';')
		{
			**ppAddr = '\0';
			(*ppAddr)++;
			goto NEXT2;
		}
	}
	return NULL;

NEXT2:
	return args_string;
}

static char *read_data(char **addr)
{
	if (addr == NULL)
		return NULL;
	if (*addr == NULL)
		return NULL;
	if ((**addr) == '\0')
		return NULL;

	// 去掉前面的空格等;
	char **ppAddr;
	for (ppAddr = addr; **ppAddr != '\0'; (*ppAddr)++)
	{
		if ((**ppAddr != ' ') && (**ppAddr != '\t'))
		{
			goto NEXT1;
		}
	}
	return NULL;

	// 检测尾部的 ","
	char *args_string;
NEXT1:
	args_string = *ppAddr;
	for (; **ppAddr != '\0'; (*ppAddr)++)
	{
		if (**ppAddr == ',')
		{
			**ppAddr = '\0';
			(*ppAddr)++;
			goto NEXT2;
		}
	}
	// 判断最后一个数据
	if (args_string != (*ppAddr))
	{
		goto NEXT2;
	}
	return NULL;

NEXT2:
	return args_string;
}

//  从文件数据中读取1行，并解析帧数据
static int read_message(int *mem_addr, int *length, struct massage *msg)
{
	if ((mem_addr == NULL) || (length == NULL) || (msg == NULL))
	{
		printf("%s,%d,read_message() error\n", __func__, __LINE__);
		return 1;
	}

	int size = *length;
	if (size <= 0)
	{
		printf("%s,%d,length <= 0\n", __func__, __LINE__);
		return 1;
	}
	// 文件尾处理
	char *file_start = (char *)(*mem_addr);
	char *file_end = file_start + size - 1;
	*(file_end + 1) = '\0'; // 末尾填0

	// 查找：一次处理一行
	// std={1AA;		08;		00, 11, 22, 33, 44, 55, 66, 77}   \n
	// ext={1555AAAA;	01;		AB	                          }   \n
	char *line_start = file_start;
	char *line_end;
	for (line_end = line_start; line_end < file_end; line_end++)
	{
		if (*line_end == '\n')
		{
			goto next1;
		}
	}
	// 最后一行为空行
	*length = 0;
	return 1;

	int line_size;
next1:
	line_size = (int)(line_end - line_start) + 1;
	*length -= line_size;
	*mem_addr = (int)line_end + 1; // 指向下一行

	static char buffer[0x400];
	memset(buffer, 0, sizeof(buffer));
	if (line_size > (sizeof(buffer) - 1))
	{
		line_size = (sizeof(buffer) - 1);
	}
	memcpy(buffer, line_start, line_size);
	line_start = buffer;

	// 处理注释
	char *commit = strchr(line_start, '#');
	if (commit != NULL)
	{
		*commit = '\0';
	}

	// 处理   { 和 }
	char *braces_end = strchr(line_start, '}');
	if (braces_end == NULL)
	{
		//xil_printf("%s,%d,not find  } \n", __func__, __LINE__);
		return 1;
	}
	*braces_end = '\0';
	char *braces_start = strchr(line_start, '{');
	if (braces_start == NULL)
	{
		//printf("%s,%d,not find	{ \n", __func__, __LINE__);
		return 1;
	}
	*braces_start = '\0';

	char *type;
	type = strstr(line_start, "std");
	if (NULL != type)
	{
		msg->type = 0; // 标准帧
		goto next2;
	}
	type = strstr(line_start, "ext");
	if (NULL != type)
	{
		msg->type = 1; // 扩展帧
		goto next2;
	}
	//printf("%s,%d,not find	std/ext \n", __func__, __LINE__);
	return 1;

	char *line_args;
	char *id_string;
next2:
	// 读取大括号中的参数
	line_args = braces_start + 1;
	id_string = read_args(&line_args);
	if (NULL == id_string)
	{
		debug_printf(" not find ID \n");
		return 1;
	}
	msg->id = strtoul(id_string, NULL, 0);

	char *length_string = read_args(&line_args);
	if (NULL == length_string)
	{
		debug_printf("not find length \n");
		return 1;
	}
	msg->length = strtoul(length_string, NULL, 0);

	// 读取数据
	for (int i = 0; i < msg->length; i++)
	{
		char *data_string = read_data(&line_args);
		if (NULL == data_string)
		{
			debug_printf("not find DATA[%d] \n", i);
			return 1;
		}
		msg->buf[i] = strtoul(data_string, NULL, 0);
	}

#if 0
	printf("%s,%d\n", __func__, __LINE__);
	printf("msg->bandrate = %d\n", msg->bandrate);
	printf("msg->type = %d\n", msg->type);
	printf("msg->id = %d\n", msg->id);
	printf("msg->flag = %d\n", msg->flag);
	printf("msg->length = %d\n", msg->length);
	printf("msg->buf[] = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
				msg->buf[0], msg->buf[1],msg->buf[2],msg->buf[3],
				msg->buf[4], msg->buf[5],msg->buf[6],msg->buf[7]);
#endif

	return 0;
}

static int can_parse_send(int device_id, char *addr_arg, int size_arg)
{
	// 读取波特率,设置波特率
	int ret = 0;
	int addr = (int)addr_arg;
	int size = size_arg;
	struct massage msg;
	memset(&msg, 0, sizeof(msg));

	ret = read_bandrate(&addr, &size, &msg);
	if (ret != 0)
	{
		debug_printf("read_bandrate(can%d) error\n",  device_id);
		goto error;
	}
	ret = openCan(device_id, &msg);
	if (ret < 0) {
		debug_printf("openCan(can%d) error\n", device_id);
		goto error;
	}

	// 读取数据，发送数据
	while (size > 0)
	{
		ret = read_message(&addr, &size, &msg);  // 读取一行
		if (ret != 0)
		 	continue;

		ret = writeCan(&msg);
		if (ret <= 0) {
			debug_printf("writeCan(can%d) error\n", device_id);
			continue;
		}
		usleep(1000);  // fix: 延时后面的帧才能发送
	}
	usleep(2000);   //fix: 最后一帧不能输出
	closeCan(device_id);
	return 0;

error:
	closeCan(device_id);
	return -1;
}


/*************************************************************************************//**
*\n 函数名称： can_send()
*\n 功能描述：
*\n            从文件中读取can报文并发送
*\n 输入参数：
*\n            int can_no  : 0=CAN0, 1=CAN1
*\n            char *file  : 数据文件
*\n 输出参数:
*\n
*\n 返 回 值:
*\n           0 成功; -1 失败; -n     错误码
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01 罗先能        2021.4.14     创建
*****************************************************************************************/
int can_send(int can_no, char *file)
{
	int ret;
	//  保存整个文件数据（最大64kBytes）
	static char  file_data[64 * 1024];

	// 1. 数据读取到内存。
	int fd = open(file, O_RDONLY | O_SYNC);
	if (fd < 0)
	{
		debug_error("open(%s) error\n", file);
	    return -1;
	}

	struct stat status;
	ret = fstat(fd, &status);
	if (ret < 0)
	{
		debug_error("fstat() error \n");
		close(fd);
	    return -1;
	}
	size_t file_size = status.st_size;
	if (file_size > sizeof(file_data))
	{
		debug_error("size=%d > %d; error \n", file_size, sizeof(file_data));
		close(fd);
	    return -1;
	}

	ssize_t read_size = read(fd, file_data, file_size);  // 文件数据读到buffer
	if (read_size < 1)
	{
		debug_error("%s,%d,read() error \n",__func__, __LINE__);
		close(fd);
	    return -1;
	}
	printf("read_size = %d, file_size =%d\n", read_size, file_size);
	close(fd);

	// 2. 解析内存中的数据，并发送can报文
	ret = can_parse_send(can_no, file_data, read_size);
	if (ret < 0)
	{
		debug_error("can_parse_send() error \n");
		return -1;
	}

	return 0;
}


